package com.ftg.learn.chapter02.ee.util;

import com.mysql.cj.jdbc.MysqlDataSource;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.logging.stdout.StdOutImpl;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.TransactionFactory;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Properties;

/**
 * 通用封装的mybatis通用类 -
 * mapper 映射器类所在文件
 * util   通用类
 * domain entity po 实体类所在包
 *
 * @author kangjx
 * @version 1.0
 * @date 2023/12/27 下午1:50
 */
public class MybatisComm {

    private SqlSession sqlSession;

    /**
     * 所有配置文件地址数组
     */
    private final String[] xmlNames;

    private final String jdbcPath;

    public MybatisComm(String[] xmlNames,String jdbcPath){
        this.xmlNames = xmlNames;
        this.jdbcPath = jdbcPath;
    }

    /**
     * 这个方法用来生成数据源,数据源可以在外部文件里面进行配置
     * @return DataSource
     */
    private DataSource initDataSource() {
        Properties p = new Properties();
        try {
            InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(this.jdbcPath);
            p.load(resourceAsStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        MysqlDataSource datasource = new MysqlDataSource();
        datasource.setURL(p.get("mysql.datasource.url").toString());
        datasource.setUser(p.get("mysql.datasource.username").toString());
        datasource.setPassword(p.get("mysql.datasource.password").toString());
        return datasource;
    }

    /**
     * 这个方法用来生成环境,环境可以在外部文件里面进行配置
     * @return Environment
     */
    private Environment initEnvironment() {
        TransactionFactory transactionFactory = new JdbcTransactionFactory();
        return new Environment("demo01",transactionFactory,initDataSource());
    }


    /**
     * 实现类xml到配置
     * XMLMapperBuilder() 方法 说明解析xml
     *              * inputStream 流
     *              * config 配置文件
     *              * path : 字符串，表示的是你要处理的xml的路径
     *              * sqlFragments  表示你的mapper里面的重用sql片段  config.getSqlFragments();
     */
    private void initXmlBuilder(Configuration config){

        if(this.xmlNames == null){
            throw new RuntimeException("xmlNames is null");
        }

        for (String path : this.xmlNames) {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
            XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(inputStream, config, path,config.getSqlFragments());
            xmlMapperBuilder.parse();
        }
    }

    /**
     * 初始化配置
     * @return Configuration
     */
    private Configuration initConfiguration(){
        Configuration config = new Configuration();

        config.setLogImpl(StdOutImpl.class);
        config.setEnvironment(initEnvironment());

        this.initXmlBuilder(config);

        return config;
    }

    /**
     * 生成SqlSessionFactory
     * @return SqlSessionFactory
     */
    private SqlSessionFactory initSqlSessionFactory(){
        return new SqlSessionFactoryBuilder().build(initConfiguration());
    }

    /**
     * 打开一个sqlsession
     * @return SqlSession
     */
    private SqlSession openSession(){
        if(Objects.isNull(this.sqlSession)){
            this.sqlSession = this.initSqlSessionFactory().openSession();
        }
        return this.sqlSession;
    }

    /**
     * 获取mapper
     * @param clazz  类关联对象
     * @param <T>    泛型
     * @return  T    实例
     */
    public <T> T getInterfaceMapper(Class<T> clazz){
        return this.openSession().getMapper(clazz);
    }

    /**
     * 关闭sqlsession
     */
    public void closeSqlSession(){
        if(Objects.nonNull(this.sqlSession)){
            this.sqlSession.flushStatements();
            this.sqlSession.clearCache();
            this.sqlSession.close();
            this.sqlSession = null;
        }
    }

    /**
     * 提交sqlsession
     */
    public void commitSqlsession(){
        if(Objects.nonNull(this.sqlSession)){
            this.sqlSession.commit();
        }
    }

    /**
     * 回滚sqlsession
     */
    public void rollbackSqlsession(){
        if(Objects.nonNull(this.sqlSession)){
            this.sqlSession.rollback();
        }
    }

}
